Add Greek (el) as beta locale#95655
Conversation
Add el to BETA_LOCALES with Ελληνικά display name. Co-authored-by: Cursor <cursoragent@cursor.com>
Add el loader to IntlStore (date-fns/locale/el), map el to Apple Sign In's el_GR locale, and load el Intl.ListFormat polyfill data. Note: src/languages/el.ts does not exist yet; typecheck passes once added in a follow-up commit. Co-authored-by: Cursor <cursoragent@cursor.com>
Add glossary and tone rules for Greek to guide translation generation (formal register, gender/case agreement). Co-authored-by: Cursor <cursoragent@cursor.com>
Generate src/languages/el.ts from en.ts via generateTranslations.ts, using the base and Greek-specific prompts. 6,048 strings translated with zero failures. Co-authored-by: Cursor <cursoragent@cursor.com>
Match the existing pattern for other AI-generated locale files; still type-checked, just not linted as hand-authored source. Co-authored-by: Cursor <cursoragent@cursor.com>
Match the existing ignorePaths pattern for other beta locales; without this, CI spell-check fails on ~10k lines of Greek text. Co-authored-by: Cursor <cursoragent@cursor.com>
Ελληνικά in LOCALES.ts's LOCALE_TO_LANGUAGE_STRING is hand-written (not covered by ignorePaths), so it needs a words entry like the other locales' native display names (Deutsch, Français, etc.). Co-authored-by: Cursor <cursoragent@cursor.com>
|
CI failed on two unrelated, pre-existing test failures (both look like date/time-bomb bugs, not caused by this PR's Greek locale changes):
Both tests use a hardcoded transaction
Tracked in Fix flaky test ReportSecondaryActionUtilsTest/ReportPreviewActionUtilsTest. |
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
Expensify Neue/Mono/New Kansas and the emoji fonts only cover Latin script and emoji glyphs. With no generic fallback at the end of the web font stack, glyphs missing from all of them (e.g. Greek) fell through to the browser's own default font, which is a serif font. Append a standard system font stack after the emoji fonts so uncovered scripts render in a sans-serif system font instead. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
main gained new copy (Agents, Rillet, onboarding, card statuses, etc.) since el.ts was generated, breaking typecheck. Regenerate incrementally against the pre-merge branch tip and manually fix Rillet export value keys the translator flattened incorrectly. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
This comment has been minimized.
This comment has been minimized.
react-native-render-html keeps only the first whitelisted face, so Greek in RenderHTML lost our system sans-serif fallbacks and rendered as serif. Remap brand faces to full platform stacks via fallbackFonts. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
|
@dubielzyk-expensify I think that newest AdHoc build should fix the pieces of serif font you pointed out. However, I'd love your advice on how to fix the LHN word wrapping issues we were seeing. It sounds like there's no shorter word that would be a natural fit for either Inbox or Account, so that gives us a few options:
|
Fill missing el.ts keys from main and satisfy ESLint naming on the HTML font fallback map key for the CSS sans-serif generic family. Co-authored-by: Cursor <cursoragent@cursor.com>
This comment has been minimized.
This comment has been minimized.
|
oh, @Expensify/design for the AdHoc to work, you must not have another Expensify tab open (or force it offline). If you have a staging or prod tab open and you switch your |
Εισερχόμενα and Λογαριασμός are too wide for the 72px tab rail. Add ZWSP break points so they wrap as Εισερχό/μενα and Λογαρια/σμός, allow Account to use 2 lines like other tabs, and lock the strings in the Greek glossary so regenerations keep the break points. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
|
I don't know what the labels translate to in Greek, but they look pretty good 🤷 😂 |
main added exportToMultipleAccounts / cardProgramAccount / cardAccount; regenerate el.ts so typecheck matches en.ts again. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@abzokhattab Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3eef94f6e5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| */ | ||
| const BETA_LOCALES = { | ||
| DE: 'de', | ||
| EL: 'el', |
There was a problem hiding this comment.
Add native Intl locale data before enabling Greek
When this adds el to the supported locale list, Greek becomes selectable on iOS/Android too, but the native Intl polyfills still only load @formatjs/intl-pluralrules data for en/es in src/libs/IntlPolyfill/index.android.ts and index.ios.ts (and the iOS NumberFormat polyfill likewise only loads en/es). With Greek selected, rendering any pluralized translation in src/languages/el.ts (for example expenseCount) will construct Intl.PluralRules('el') after the forced polyfill has no Greek data loaded, causing missing-locale runtime failures on native; please load the Greek Intl polyfill data alongside making the locale selectable.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
@MelvinBot does this concern affect all locales other than English and Spanish, or just Greek? If it does concern other locales, please create a new GitHub issue in this repo, label it weekly, and assign to me
There was a problem hiding this comment.
This affects all locales other than English and Spanish — not just Greek. The native polyfills hardcode en/es data (index.android.ts:15-17, index.ios.ts:16-18, polyfillNumberFormat.ts:32-34), and this PR only wires up Greek for ListFormat — nothing Greek-specific about the pluralrules/NumberFormat gap. It's a pre-existing issue shared by every beta locale (de, el, fr, it, ja, nl, pl, pt-BR, zh-hans).
One correction to the concern above: @formatjs/intl-pluralrules polyfill-force does not crash on a missing locale — ResolveLocale falls back to the first-loaded default (en). So instead of a runtime failure, non-en/es locales silently use English plural rules:
- Unaffected in practice: locales sharing English's
one/othercategories —de,el(Greek isone/other),fr,it,nl,pt-BR, andja/zh-hans(otheronly). So Greek'sexpenseCountwill actually render correctly via theenfallback. - Actually mis-served today: Polish (
pl), which hasone/few/many/other— English rules can only ever yieldone/other, so itsfew/manyforms never fire. Any future locale with non-English plural categories (Russian, Arabic, Czech…) would hit the same. - NumberFormat is only forced on devices with stale ICU, and again only loads
en/es.
Filed as #96335, labeled Weekly and assigned to you. Suggested fix in there: load the pluralrules/numberformat data for the active locale dynamically, the same way IntlStore already loads translations, date-fns, and ListFormat data per locale.
|
Hi, is c+ review needed? just confirming before reviewing |
|
Sure @abzokhattab, go for it 👍🏼 |
Keep Greek in BETA_LOCALES after French was promoted to fully supported. Co-authored-by: Cursor <cursoragent@cursor.com>
Incrementally translate keys added since the pre-merge tip. Co-authored-by: Cursor <cursoragent@cursor.com>
|
REALLY kicking myself that when Rory asked for a design review I didn't reply simply: "It's all Greek to me" Jeeeeeeeeeeeeeeeeze what a wasted opportunity. I will try to do better. |
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
|
FYI: It's important that this PR be up-to-date with main before it is merged. More important than with other PRs so that we know Greek translations are present for all strings in other languages on main. Not a huge deal if we miss it; it would just cause typecheck to start failing on main, which is a bit disruptive |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
Reviewing after finishing another task today |








Explanation of Change
Adds Greek (
el) as a new beta locale. RegisterselinLOCALES.ts, wires runtime loading inIntlStore(translations +date-fnslocale), maps Apple Sign In'sel_GRlocale, loads GreekIntl.ListFormatpolyfill data, adds a Greek translation prompt/glossary, and generatessrc/languages/el.tsfromen.ts(6,048 strings, zero translation failures). Excludes the generated file from ESLint and cspell, matching every other beta locale's pattern.This lands the infra prerequisite for Add Greek as a language to E/App, part of the translator-hiring epic #504749. Greek ships as beta: AI-generated, unaudited, no localized emoji keywords — same limitations as
de/fr/ja/etc. Promoting to fully-supported happens after expert audit in a follow-up.Fixed Issues
$ https://github.com/Expensify/Expensify/issues/657039
PROPOSAL:
Tests
undefined/[object Object], and no missing-key errors.Offline tests
N/A — locale files are bundled at build time; no network-dependent behavior changes.
QA Steps
Same as Tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)Avatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
N/A — web-only locale infra change, no native platform code touched.
Android: mWeb Chrome
N/A — see MacOS: Chrome / Safari for representative web coverage.
iOS: Native
N/A — web-only locale infra change, no native platform code touched.
iOS: mWeb Safari
N/A — see MacOS: Chrome / Safari for representative web coverage.
MacOS: Chrome / Safari